```vue
<template>
  <div class="app-container">
    <!-- 搜索区域 -->
    <el-card class="search-wrapper">
      <el-form
        :model="queryParams"
        ref="queryForm"
        size="small"
        :inline="true"
        v-show="showSearch"
        label-width="80px"
      >
        <el-form-item label="用户ID" prop="userId">
          <el-input
            v-model="queryParams.userId"
            placeholder="请输入用户ID"
            clearable
            @keyup.enter="handleQuery"
            class="search-input"
          />
        </el-form-item>
        <el-form-item label="地址" prop="address">
          <el-input
            v-model="queryParams.address"
            placeholder="请输入地址"
            clearable
            @keyup.enter="handleQuery"
            class="search-input"
          />
        </el-form-item>
        <el-form-item label="用户昵称" prop="userName">
          <el-input
            v-model="queryParams.userName"
            placeholder="请输入用户昵称"
            clearable
            @keyup.enter="handleQuery"
            class="search-input"
          />
        </el-form-item>
        <el-form-item label="区域" prop="area">
          <el-input
            v-model="queryParams.area"
            placeholder="请输入区域"
            clearable
            @keyup.enter="handleQuery"
            class="search-input"
          />
        </el-form-item>
        <el-form-item>
          <el-button
            type="primary"
            icon="el-icon-search"
            size="mini"
            @click="handleQuery"
            class="search-button"
          >搜索</el-button>
          <el-button
            icon="el-icon-refresh"
            size="mini"
            @click="resetQuery"
            class="reset-button"
          >重置</el-button>
        </el-form-item>
      </el-form>
    </el-card>

    <!-- 操作按钮区域 -->
    <el-card class="operation-wrapper">
      <el-row :gutter="12" class="mb8">
        <el-col :span="1.5">
          <el-button
            type="primary"
            plain
            icon="el-icon-plus"
            size="mini"
            @click="handleAdd"
            v-hasPermi="['supply:address:add']"
            class="operation-button"
          >新增</el-button>
        </el-col>
        <el-col :span="1.5">
          <el-button
            type="success"
            plain
            icon="el-icon-edit"
            size="mini"
            :disabled="single"
            @click="handleUpdate"
            v-hasPermi="['supply:address:edit']"
            class="operation-button"
          >修改</el-button>
        </el-col>
        <el-col :span="1.5">
          <el-button
            type="danger"
            plain
            icon="el-icon-delete"
            size="mini"
            :disabled="multiple"
            @click="handleDelete"
            v-hasPermi="['supply:address:remove']"
            class="operation-button"
          >删除</el-button>
        </el-col>
        <el-col :span="1.5">
          <el-button
            type="warning"
            plain
            icon="el-icon-download"
            size="mini"
            @click="handleExport"
            v-hasPermi="['supply:address:export']"
            class="operation-button"
          >导出</el-button>
        </el-col>
        <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
      </el-row>
    </el-card>

    <!-- 地址展示区域 -->
    <div class="address-grid" v-loading="loading">
      <el-empty
        v-if="!Object.keys(groupedAddresses).length"
        description="暂无地址数据"
        image-size="120"
      ></el-empty>
      <el-row :gutter="24" v-else>
        <el-col
          :xs="24"
          :sm="12"
          :md="8"
          v-for="(group, area) in groupedAddresses"
          :key="area"
          class="area-col"
        >
          <el-card class="area-card" :body-style="{ padding: '0px' }">
            <div class="area-header">
              <span class="area-name">{{ area || '未分类区域' }}</span>
              <span class="address-count">{{ group.length }}个地址</span>
            </div>
            <div class="area-content">
              <!-- 默认显示区域的第一个地址 -->
              <div class="default-view">
                <div class="address-item">
                  <i class="el-icon-location-information"></i>
                  <span class="address-text">{{ group[0].address || '暂无地址' }}</span>
                </div>
                <div class="user-info">
                  <span class="user-name">{{ group[0].userName || '未知用户' }}</span>
                  <el-tag size="mini" class="area-tag">{{ group[0].area || '未分类' }}</el-tag>
                </div>
              </div>
              <!-- 悬浮时显示的详细信息 -->
              <div class="hover-view">
                <div class="address-list" style="height: 100px">
                  <div class="address-item" v-for="item in group" :key="item.id">
                    <div class="address-info">
                      <div class="info-row header">
                        <span class="user-name">{{ item.userName || '未知用户' }}</span>
                        <span class="user-id">ID: {{ item.userId }}</span>
                      </div>
                      <div class="info-row">
                        <span class="label">地址：</span>
                        <span class="address-text">{{ item.address || '暂无地址' }}</span>
                      </div>
                      <div class="info-row time">
                        <span class="create-time">创建：{{ formatTime(item.createTime) }}</span>
                        <span class="update-time">更新：{{ formatTime(item.updateTime) }}</span>
                      </div>
                      <div class="info-row" v-if="item.remark">
                        <span class="label">备注：</span>
                        <span class="remark-text">{{ item.remark }}</span>
                      </div>
                    </div>
                    <div class="operations">
                      <el-button
                        type="text"
                        icon="el-icon-edit"
                        @click.stop="handleUpdate(item)"
                        v-hasPermi="['supply:address:edit']"
                        class="operation-text"
                      >编辑</el-button>
                      <el-button
                        type="text"
                        icon="el-icon-delete"
                        @click.stop="handleDelete(item)"
                        v-hasPermi="['supply:address:remove']"
                        class="operation-text danger"
                      >删除</el-button>
                    </div>
                  </div>
                </div>
              </div>
            </div>
          </el-card>
        </el-col>
      </el-row>
    </div>

    <!-- 添加或修改地址对话框 -->
    <el-dialog
      :title="addressForm.id ? '修改收货地址' : '新增收货地址'"
      :visible.sync="open"
      width="500px"
      append-to-body
      :close-on-click-modal="false"
      :close-on-press-escape="false"
      :before-close="handleAddressDialogClose"
    >
      <el-form :model="addressForm" ref="addressForm" :rules="addressRules" label-width="100px">
        <el-form-item label="地址标签" prop="userName">
          <el-input
            v-model="addressForm.userName"
            placeholder="请输入地址标签，如：家、公司、学校"
            maxlength="10"
            show-word-limit
          ></el-input>
        </el-form-item>

        <el-form-item label="区域" prop="area">
          <el-select v-model="addressForm.area" placeholder="请选择区域" clearable style="width: 100%">
            <el-option
              v-for="dict in dict.type.address_area"
              :key="dict.value"
              :label="dict.label"
              :value="dict.value"></el-option>
          </el-select>
        </el-form-item>

        <el-form-item label="所在地区" prop="address">
          <el-cascader
            v-model="selectedRegion"
            :options="regionData"
            :props="{
              expandTrigger: 'hover',
              value: 'label',
              label: 'label',
              children: 'children'
            }"
            @change="handleAddressChange"
            placeholder="请选择省/市/区/街道"
            style="width: 100%"
          ></el-cascader>
        </el-form-item>

        <el-form-item label="详细地址" prop="address">
          <el-input
            v-model="addressForm.address"
            type="textarea"
            :rows="3"
            placeholder="请输入详细地址，如：街道、门牌号等"
          ></el-input>
        </el-form-item>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button @click="cancel">取 消</el-button>
        <el-button type="primary" @click="submitAddress">确 定</el-button>
      </div>
    </el-dialog>
  </div>
</template>

<script>
import { listAddress, getAddress, delAddress, addAddress, updateAddress } from "@/api/supply/address";
import { getUserProfile } from "@/api/system/user";
import { getDicts } from "@/api/system/dict/data";

export default {
  name: "Address",
  dicts: ['address_area'],
  data() {
    return {
      // 遮罩层
      loading: true,
      // 选中数组
      ids: [],
      // 非单个禁用
      single: true,
      // 非多个禁用
      multiple: true,
      // 显示搜索条件
      showSearch: true,
      // 总条数
      total: 0,
      // 用户地址表格数据
      addressList: [],
      // 弹出层标题
      title: "",
      // 是否显示弹出层
      open: false,
      // 查询参数
      queryParams: {
        pageNum: 1,
        pageSize: 10,
        userId: null,
        address: null,
        userName: null,
        area: null,
      },
      // 表单参数
      addressForm: {
        address: '', // 只存储详细地址
        userId: '',
        userName: '',
        area: ''
      },
      // 表单校验
      addressRules: {
        address: [{ required: true, message: "地址不能为空", trigger: "blur" }],
        area: [{ required: true, message: "区域不能为空", trigger: "blur" }],
      },
      selectedRegion: [], // 用于存储级联选择器的值
      regionText: '', // 用于存储所在地区的文本
      regionData: [
        {
          value: '河南省',
          label: '河南省',
          children: [
            {
              value: '焦作市',
              label: '焦作市',
              children: [
                {
                  value: '解放区',
                  label: '解放区',
                  children: [
                    { value: '民主街道', label: '民主街道' },
                    { value: '民生街道', label: '民生街道' }
                  ]
                },
                {
                  value: '中站区',
                  label: '中站区',
                  children: [
                    { value: '许衡街道', label: '许衡街道' },
                    { value: '李封街道', label: '李封街道' }
                  ]
                }
              ]
            }
          ]
        }
      ],
    };
  },
  computed: {
    groupedAddresses() {
      const groups = {};
      console.log("开始处理地址数据，原始数据:", JSON.stringify(this.addressList));

      if (this.addressList && this.addressList.length > 0) {
        this.addressList.forEach((item) => {
          const areaKey = item.area || "未分类区域";
          console.log("处理地址项:", {
            area: areaKey,
            id: item.id,
            address: item.address,
            userName: item.userName
          });

          if (!groups[areaKey]) {
            groups[areaKey] = [];
          }
          const addressItem = {
            id: item.id,
            userId: item.userId,
            userName: item.userName || "未知用户",
            address: item.address || "暂无地址",
            area: item.area || "未分类区域",
            createTime: item.createTime,
            updateTime: item.updateTime,
            remark: item.remark,
          };
          groups[areaKey].push(addressItem);
        });
      }

      console.log("分组后的地址数据:", JSON.stringify(groups));
      return groups;
    },
  },
  created() {
    this.getList();
    this.getUser();
    this.getDicts("address_area");
    this.getRegionData();
  },
  mounted() {
    // 添加这个生命周期钩子来检查DOM结构
    this.$nextTick(() => {
      console.log("组件挂载完成，检查DOM结构");
      const cards = document.querySelectorAll('.area-card');
      console.log("找到的地址卡片数量:", cards.length);
      cards.forEach((card, index) => {
        const hoverView = card.querySelector('.hover-view');
        const defaultView = card.querySelector('.default-view');
        console.log(`卡片 ${index + 1} 的DOM结构:`, {
          hasHoverView: !!hoverView,
          hasDefaultView: !!defaultView,
          hoverViewStyle: hoverView ? window.getComputedStyle(hoverView) : null,
          defaultViewStyle: defaultView ? window.getComputedStyle(defaultView) : null
        });
      });
    });
  },
  methods: {
    /** 查询用户地址列表 */
    getList() {
      this.loading = true;
      console.log("开始获取地址列表，查询参数:", this.queryParams);

      listAddress(this.queryParams)
        .then((response) => {
          console.log("接收到的原始数据:", response);
          if (!response.rows) {
            this.addressList = [response];
          } else {
            this.addressList = response.rows;
          }
          console.log("处理后的地址列表数据:", this.addressList);
          this.total = response.total || this.addressList.length;
          this.loading = false;
        })
        .catch((error) => {
          console.error("获取地址列表失败:", error);
          this.$modal.msgError("获取地址列表失败，请稍后重试");
          this.loading = false;
        });
    },
    /** 格式化时间 */
    formatTime(time) {
      if (!time) return "未知";
      return new Date(time).toLocaleString("zh-CN", {
        year: "numeric",
        month: "2-digit",
        day: "2-digit",
        hour: "2-digit",
        minute: "2-digit",
        second: "2-digit",
      });
    },
    // 取消按钮
    cancel() {
      this.handleAddressDialogClose();
    },
    // 表单重置
    reset() {
      this.selectedRegion = [];
      this.regionText = '';
      this.addressForm = {
        address: '',
        userId: this.user.userId,
        userName: '',
        area: ''
      };
      this.resetForm("addressForm");
    },
    /** 搜索按钮操作 */
    handleQuery() {
      this.queryParams.pageNum = 1;
      this.getList();
    },
    /** 重置按钮操作 */
    resetQuery() {
      this.resetForm("queryForm");
      this.handleQuery();
    },
    // 多选框选中数据
    handleSelectionChange(selection) {
      this.ids = selection.map((item) => item.id);
      this.single = selection.length !== 1;
      this.multiple = !selection.length;
    },
    /** 新增按钮操作 */
    handleAdd() {
      this.reset();
      this.open = true;
      this.title = "新增收货地址";
    },
    /** 修改按钮操作 */
    handleUpdate(row) {
      this.reset();
      const id = row.id || this.ids;
      getAddress(id).then((response) => {
        this.addressForm = response.data;
        // 处理地址回显
        if (this.addressForm.address) {
          // 尝试从完整地址中提取所在地区
          const addressParts = this.addressForm.address.split(' ');
          if (addressParts.length > 1) {
            // 假设前几部分是所在地区，最后一部分是详细地址
            const regionParts = addressParts.slice(0, -1);
            this.regionText = regionParts.join(' ');
            this.addressForm.address = addressParts[addressParts.length - 1];

            // 尝试匹配级联选择器的值
            this.selectedRegion = this.findRegionPath(this.regionData, regionParts);
          }
        }
        this.open = true;
      });
    },
    /** 提交按钮 */
    submitForm() {
      this.$refs["form"].validate((valid) => {
        if (valid) {
          if (this.addressForm.id != null) {
            updateAddress(this.addressForm).then((response) => {
              this.$modal.msgSuccess("修改成功");
              this.open = false;
              this.getList();
            });
          } else {
            addAddress(this.addressForm).then((response) => {
              this.$modal.msgSuccess("新增成功");
              this.open = false;
              this.getList();
            });
          }
        }
      });
    },
    /** 删除按钮操作 */
    handleDelete(row) {
      const ids = row.id || this.ids;
      this.$modal
        .confirm('是否确认删除用户地址编号为"' + ids + '"的数据项？')
        .then(() => {
          return delAddress(ids);
        })
        .then(() => {
          this.getList();
          this.$modal.msgSuccess("删除成功");
        })
        .catch(() => {});
    },
    /** 导出按钮操作 */
    handleExport() {
      this.download(
        "supply/address/export",
        {
          ...this.queryParams,
        },
        `address_${new Date().getTime()}.xlsx`
      );
    },
    tableHeaderStyle() {
      return {
        backgroundColor: "#f5f7fa",
        color: "#606266",
        fontWeight: "bold",
        height: "45px",
      };
    },
    tableCellStyle() {
      return {
        height: "40px",
      };
    },
    // 处理地址选择变化
    handleAddressChange(value) {
      if (value && value.length > 0) {
        // 只更新所在地区的文本，不影响详细地址
        this.regionText = value.join(' ');
      }
    },
    // 提交新增地址
    submitAddress() {
      this.$refs["addressForm"].validate(async (valid) => {
        if (valid) {
          try {
            // 提交时组合所在地区和详细地址
            const fullAddress = this.regionText ? `${this.regionText} ${this.addressForm.address}` : this.addressForm.address;

            const addressData = {
              userId: this.user.userId,
              userName: this.addressForm.userName,
              area: this.addressForm.area,
              address: fullAddress
            };

            if (this.addressForm.id) {
              addressData.id = this.addressForm.id;
              await updateAddress(addressData);
              this.$modal.msgSuccess("修改成功");
            } else {
              await addAddress(addressData);
              this.$modal.msgSuccess("新增成功");
            }
            this.open = false;
            this.getList();
          } catch (error) {
            this.$message.error('操作失败：' + error.message);
          }
        }
      });
    },
    // 处理地址对话框关闭
    handleAddressDialogClose(done) {
      this.$modal.confirm('确认关闭？未保存的数据将会丢失').then(() => {
        this.reset();
        this.open = false;
        if (done) {
          done();
        }
      }).catch(() => {});
    },
    // 获取省市区数据
    getRegionData() {
      // 这里使用 Element UI 内置的中国省市区数据
      import('element-china-area-data').then(module => {
        this.regionData = module.regionData;
      });
    },
    // 获取用户信息
    getUser() {
      getUserProfile().then(response => {
        this.user = response.data;
      }).catch(error => {
        console.error('获取用户信息失败', error);
      });
    },
    // 查找地区路径
    findRegionPath(regionData, targetParts) {
      const result = [];
      const findPath = (data, target, currentPath = []) => {
        for (const item of data) {
          const newPath = [...currentPath, item.label];
          if (target.includes(item.label)) {
            if (item.children) {
              const childResult = findPath(item.children, target, newPath);
              if (childResult) return childResult;
            } else {
              return newPath;
            }
          }
          if (item.children) {
            const childResult = findPath(item.children, target, currentPath);
            if (childResult) return childResult;
          }
        }
        return null;
      };

      return findPath(regionData, targetParts) || [];
    },
  },
};
</script>

<style lang="scss" scoped>
.app-container {
  padding: 24px;
  background: linear-gradient(180deg, #f7f9fc 0%, #e8edf5 100%);
  min-height: calc(100vh - 84px);
  font-family: "PingFang SC", "Microsoft YaHei", sans-serif;
}

/* 搜索区域 */
.search-wrapper {
  margin-bottom: 24px;
  border-radius: 12px;
  background: #ffffff;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
  transition: all 0.3s;

  &:hover {
    box-shadow: 0 6px 20px rgba(0, 0, 0, 0.12);
  }

  .el-form {
    padding: 20px 24px;

    .el-form-item {
      margin-bottom: 16px;
      margin-right: 24px;

      .search-input {
        width: 220px;

        :deep(.el-input__inner) {
          border-radius: 8px;
          height: 36px;
          line-height: 36px;
          border: 1px solid #dcdfe6;
          transition: all 0.3s;
          font-size: 14px;

          &:hover,
          &:focus {
            border-color: #409eff;
            box-shadow: 0 0 6px rgba(64, 158, 255, 0.3);
          }
        }
      }

      :deep(.el-form-item__label) {
        font-size: 14px;
        color: #333333;
        font-weight: 500;
      }
    }

    .search-button,
    .reset-button {
      padding: 8px 20px;
      border-radius: 8px;
      font-size: 14px;
      transition: all 0.3s;

      &:hover {
        transform: translateY(-2px);
        box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
      }
    }

    .search-button {
      background: linear-gradient(90deg, #409eff 0%, #66b1ff 100%);
      border: none;
    }

    .reset-button {
      border: 1px solid #dcdfe6;
    }
  }
}

/* 操作按钮区域 */
.operation-wrapper {
  margin-bottom: 24px;
  padding: 16px 24px;
  border-radius: 12px;
  background: #ffffff;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
  transition: all 0.3s;

  &:hover {
    box-shadow: 0 6px 20px rgba(0, 0, 0, 0.12);
  }

  .operation-button {
    padding: 8px 16px;
    border-radius: 8px;
    font-size: 14px;
    transition: all 0.3s;

    &:hover {
      transform: translateY(-2px);
      box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
    }

    &[disabled] {
      &:hover {
        transform: none;
        box-shadow: none;
      }
    }
  }
}

/* 地址展示区域 */
.address-grid {
  margin-top: 16px;

  .area-col {
    margin-bottom: 24px;
  }

  .area-card {
    border-radius: 12px;
    background: #ffffff;
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
    transition: all 0.3s;
    position: relative;
    overflow: visible;

    &:hover {
      transform: translateY(-4px) scale(1.02);
      box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);

      .hover-view {
        opacity: 1 !important;
        transform: translateY(0) !important;
        pointer-events: auto !important;
        visibility: visible !important;
        z-index: 1000 !important; /* 提高悬浮视图的层级 */
      }

      .default-view {
        opacity: 0;
        visibility: hidden;
      }
    }

    .area-header {
      padding: 16px 20px;
      background: linear-gradient(90deg, #e6f0ff 0%, #f0f7ff 100%);
      border-bottom: 1px solid #e6e9f0;
      display: flex;
      justify-content: space-between;
      align-items: center;

      .area-name {
        font-size: 16px;
        font-weight: 600;
        color: #1f2a44;
      }

      .address-count {
        font-size: 13px;
        color: #909399;
      }
    }

    .area-content {
      position: relative;
      min-height: 120px;
      overflow: visible;

      .default-view {
        padding: 20px;
        transition: all 0.3s;
        visibility: visible;
        position: relative;
        z-index: 1;
      }

      .hover-view {
        position: absolute;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
        background: #ffffff;
        padding: 16px;
        opacity: 0;
        transform: translateY(10px);
        transition: all 0.3s;
        pointer-events: none;
        z-index: 1000; /* 提高悬浮视图的层级 */
        border-radius: 0 0 12px 12px;
        box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15); /* 增强阴影效果 */
        visibility: hidden;

        .address-list {
          max-height: 280px;
          overflow-y: auto;
          padding-right: 8px;

          .address-item {
            padding: 12px;
            border-bottom: 1px solid #f0f2f5;
            display: flex;
            justify-content: space-between;
            align-items: flex-start;
            transition: all 0.3s;
            background: #ffffff;

            &:hover {
              background: #f8f9fb;
            }
          }
        }
      }
    }
  }
}

/* 弹窗样式 */
.custom-dialog {
  :deep(.el-dialog) {
    border-radius: 16px;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
    background: #ffffff;

    .el-dialog__header {
      padding: 20px 24px;
      background: linear-gradient(90deg, #e6f0ff 0%, #f0f7ff 100%);
      border-bottom: 1px solid #e6e9f0;

      .el-dialog__title {
        font-size: 18px;
        font-weight: 600;
        color: #1f2a44;
      }
    }

    .el-dialog__body {
      padding: 24px;
    }

    .el-dialog__footer {
      padding: 16px 24px;
      border-top: 1px solid #e6e9f0;

      .el-button {
        padding: 10px 20px;
        border-radius: 8px;
        font-size: 14px;
        transition: all 0.3s;

        &:hover {
          transform: translateY(-2px);
          box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
        }

        &.el-button--primary {
          background: linear-gradient(90deg, #409eff 0%, #66b1ff 100%);
          border: none;
        }
      }
    }
  }

  :deep(.el-form-item) {
    margin-bottom: 24px;

    .el-form-item__label {
      font-size: 14px;
      font-weight: 500;
      color: #333333;
    }

    .el-input__inner {
      height: 40px;
      line-height: 40px;
      border-radius: 8px;
      font-size: 14px;
      transition: all 0.3s;

      &:hover,
      &:focus {
        border-color: #409eff;
        box-shadow: 0 0 6px rgba(64, 158, 255, 0.3);
      }
    }
  }
}

/* 全局覆盖 */
:deep(.el-card) {
  border: none;
}

:deep(.el-empty) {
  padding: 48px 0;
  background: #ffffff;
  border-radius: 12px;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);

  .el-empty__description {
    font-size: 14px;
    color: #606266;
  }
}
</style>
```
